package com.atguigu.tingshu.order.adapter.impl;

import com.atguigu.tingshu.account.client.UserAccountFeignClient;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.model.order.LocalMsg;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.order.adapter.PayWay;
import com.atguigu.tingshu.order.mapper.LocalMsgMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.vo.account.AccountLockResultVo;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;


@Component
public class RechargePayWayImpl implements PayWay {

    @Autowired
    private OrderInfoService orderInfoService;

    @Qualifier("com.atguigu.tingshu.account.client.UserAccountFeignClient")
    @Autowired
    private UserAccountFeignClient userAccountFeignClient;

    @Autowired
    private RabbitService rabbitService;

    @Autowired
    private LocalMsgMapper localMsgMapper;

    @Override
    public Boolean supportPayWay(String payWay) {
        // 判断传入的支付方式是否是零钱
        return SystemConstant.ORDER_PAY_ACCOUNT.equals(payWay);
    }



    /**
     * 本地定时任务（TODO:xxl-job）
     * 定时扫描本地消息表，处理状态为0的消息。
     * 该方法每小时执行一次，查询本地消息表中状态为0的消息，并通过RabbitMQ发送解锁账户和减少账户余额的消息。
     */
    // 定时任务，每小时执行一次
    @Scheduled(fixedDelay = 1000 * 60 * 60)
    public void scanLocalMsg() {
        // 1.扫描本地消息表(性能可能会低)
        LambdaQueryWrapper<LocalMsg> wrapper = new LambdaQueryWrapper<>();
        // 设置查询条件，筛选状态为0的消息
        wrapper.eq(LocalMsg::getStatus, 0);
        // 执行查询，获取符合条件的消息列表
        List<LocalMsg> localMsgs = localMsgMapper.selectList(wrapper);
        // 遍历消息列表，发送消息
        for (LocalMsg localMsg : localMsgs) {
            // 发送解锁账户消息
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_UNLOCK, localMsg.getMsgContent());
            // 发送减少账户余额消息
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_MINUS, localMsg.getMsgContent());
        }
    }



    /**
     * 处理支付方式
     *
     * @param orderInfoVo 订单信息对象，包含订单详细信息
     * @param orderNo 订单编号，用于标识特定订单
     * @param userId 用户ID，用于关联用户信息
     * 此方法主要用于处理用户的支付方式，包括检查账户余额是否充足、保存订单信息、
     * 以及通过消息队列进行账户余额的扣减或解锁操作。
     */
    @Override
    public void payWay(OrderInfoVo orderInfoVo, String orderNo, Long userId) {

        // 1.判断钱是否够用(rpc方式同步调用账户微服务获取账户余额锁定信息)
        AccountLockVo accountLockVo = prepareAccountData(orderInfoVo, userId, orderNo);
        Result<AccountLockResultVo> accountLockResultVoResult = userAccountFeignClient.checkAndLockAccount(accountLockVo);

        Integer code = accountLockResultVoResult.getCode();
        if (code != 200) {
            //锁定失败 抛出异常
            throw new GuiguException(ResultCodeEnum.ACCOUNT_LOCK_ERROR);
        }
        // 2.保存订单
        try {
            // 3.保存订单信息
            orderInfoService.saveOrderInfo(orderNo, orderInfoVo, userId);
            // 4.初始化消息表
            orderInfoService.saveLocalMsg(orderNo);
            // 真正扣减余额
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_MINUS, orderNo);
            //处理支付成功
            orderInfoService.paySuccess(orderNo);

        } catch (GuiguException e) {
            // 反向去修改账户微服务下的账户信息（user_account的锁定账户余额和可用账户余额）
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_UNLOCK, orderNo);
        } catch (Exception e) {
            rabbitService.sendMessage(MqConst.EXCHANGE_ACCOUNT, MqConst.ROUTING_ACCOUNT_MINUS, orderNo);
        }

    }



    /**
     * 准备账户数据，用于锁定用户账户信息
     *
     * @param orderInfoVo 订单信息视图对象，包含订单详细信息
     * @param userId 用户ID，用于标识用户
     * @param orderNo 订单号，用于标识特定的订单
     * @return 返回一个填充了订单和用户信息的AccountLockVo对象
     */
    private AccountLockVo prepareAccountData(OrderInfoVo orderInfoVo, Long userId, String orderNo) {
        // 创建一个AccountLockVo对象用于存储账户锁定信息
        AccountLockVo accountLockVo = new AccountLockVo();

        // 设置订单号，用于关联特定的订单
        accountLockVo.setOrderNo(orderNo);
        // 设置用户ID，明确是哪个用户的账户
        accountLockVo.setUserId(userId);
        // 设置订单金额，即用户账户中需要锁定的金额
        accountLockVo.setAmount(orderInfoVo.getOrderAmount()); // 实际金额
        // 设置订单内容，这里取订单详情列表中的第一个商品名称作为代表
        accountLockVo.setContent(orderInfoVo.getOrderDetailVoList().get(0).getItemName()); // 买的内容

        // 返回填充好数据的AccountLockVo对象
        return accountLockVo;
    }



}
